package edu.gatech.cs4220;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.location.*;
import android.util.Log;
import android.view.View;

import java.io.IOException;

public class geoprofiles extends Activity
{
	// XXX refactor to use user preferences
	private static final float MIN_METER_CHANGE_UPDATE = 10;
	private static final long MIN_MILI_CHANGE_UPDATE = 60000;
	private static final Criteria ACCURACY_NEEDED = new Criteria();
	private static final String PROFILE_FILE_NAME = "profiles.list";
	static final String LOG_NAME = "geoprofiles";
	
	private static LocationProfileSet currentProfileSet = null;
	
	//Because other modules will need this
	static android.content.Context APP_CONTEXT = null;

	private LocationManager currentLocMan;

	static
	{
		ACCURACY_NEEDED.setAccuracy(Criteria.ACCURACY_FINE);
		ACCURACY_NEEDED.setAltitudeRequired(false);
		ACCURACY_NEEDED.setBearingRequired(false);
		ACCURACY_NEEDED.setPowerRequirement(Criteria.POWER_MEDIUM);
	}

	private ProfileListenerEngine currentProfileListener;

	static final void logErrorAndThrowAssertion(String message, Throwable err)
	{
		Log.e(LOG_NAME, message, err);
		throw (AssertionError)(new AssertionError(message)).initCause(err);
	}

	static final void logErrorAndThrowAssertion(String message)
	{
		Log.e(LOG_NAME, message);
		throw new AssertionError(message);
	}
	
	static final void logAssertionAndThrowAssertion(String message, Throwable err)
	{
		Log.wtf(LOG_NAME, message, err);
		throw (AssertionError)(new AssertionError(message)).initCause(err);
	}

	static final void logAssertionAndThrowAssertion(String message)
	{
		Log.wtf(LOG_NAME, message);
		throw new AssertionError(message);
	}

	public static LocationProfileSet getCurrentProfiles()
	{
		return currentProfileSet;
	}
	
	static void setCurrentProfiles(LocationProfileSet newSet)
	{
		currentProfileSet = newSet;
	}
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		//Following is test code
		// Allow the superclass to initialize its state
		super.onCreate(savedInstanceState);
		APP_CONTEXT = getApplicationContext();
		setContentView(R.layout.main);
		try {
			currentProfileSet = loadProfiles();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		/*LocationProfile testProfile1 = new LocationProfile(this);
		LocationProfile testProfile2 = new LocationProfile(this);
		LocationProfile testProfileDefault = new LocationProfile(this);
		LocationProfileSet testSet = new LocationProfileSet(testProfileDefault);
		testProfile1.addPoint(new LocationProfilePoint(10, 10, 10));
		testProfile1.addPoint(new LocationProfilePoint(50, 50, 10));
		
		testProfile2.addPoint(new LocationProfilePoint(30, 30, 5));
		testProfile1.setEnabled();
		testProfile2.setEnabled();
		testSet.getProfiles().add(testProfile1);
		testSet.getProfiles().add(testProfile2);
		
		LocationProfile testResult = testSet.getClosestElegibleProfile(new LocationProfilePoint(80, 80, 2));
		
		android.widget.TextView mainText = new android.widget.TextView(this);
		mainText.setText(Boolean.toString(
			testResult == testProfileDefault));
		setContentView(mainText);*/
		
		
		//Following is the main code
		

		/*
		 * super.onCreate(savedInstanceState); setContentView(R.layout.main);
		 * LocationManager locMan =
		 * (LocationManager)this.getSystemService(LOCATION_SERVICE); Criteria
		 * accuracyCriteria = new Criteria();
		 * accuracyCriteria.setAccuracy(Criteria.ACCURACY_FINE); String bestProv
		 * = locMan.getBestProvider(accuracyCriteria, true); final TextView
		 * mainText = new TextView(this); mainText.setText(NO_CURRENT_LOC);
		 * 
		 * LocationListener locListen = new LocationListener() {
		 * 
		 * @Override public void onLocationChanged(Location location) {
		 * mainText.setText(location == null ? NO_CURRENT_LOC :
		 * location.toString()); }
		 * 
		 * @Override public void onProviderEnabled(String provider) { //Do
		 * nothing, we don't need to know this info }
		 * 
		 * @Override public void onProviderDisabled(String provider) { //Do
		 * nothing, we don't need to know this info }
		 * 
		 * @Override public void onStatusChanged(String provider, int status,
		 * Bundle extras) { //Do nothing, we don't need to know this info } };
		 * locMan.requestLocationUpdates(bestProv, 0, 0, locListen);
		 * this.setContentView(mainText);
		 */
	}

	@Override
	public void finish()
	{
		// Make sure to stop the daemon if the app is closed
		stopDaemon(currentLocMan);
	}

	void saveProfiles(LocationProfileSet toSave) throws IOException
	{
		java.io.ByteArrayOutputStream temp = new java.io.ByteArrayOutputStream();
		(new java.io.ObjectOutputStream(temp)).writeObject(toSave);
		java.io.FileOutputStream outStream = null;
		try
		{
			outStream = openFileOutput(PROFILE_FILE_NAME, MODE_PRIVATE);
			outStream.write(temp.toByteArray());
		}
		finally
		{
			if(outStream != null)
				outStream.close();
		}
	}
	
	LocationProfileSet loadProfiles() throws IOException
	{
		java.io.FileInputStream inStream = null;
		try
		{
			try
			{
				inStream = openFileInput(PROFILE_FILE_NAME);
			}
			catch(java.io.FileNotFoundException err)
			{
				//No file, return a blank set
				return LocationProfileSet.generateBlankSet(getApplicationContext());
			}
			java.io.BufferedInputStream bufferedIn = new java.io.BufferedInputStream(inStream);
			java.io.ByteArrayOutputStream tempWriteTo = new java.io.ByteArrayOutputStream();
			int readValue = bufferedIn.read();
			//Sadly we have to do this in order to see if we have any file
			while(readValue != -1)
			{
				tempWriteTo.write(readValue);
				readValue = bufferedIn.read();
			}
			byte[] fileBytes = tempWriteTo.toByteArray();
			tempWriteTo.close();
			//If it was an empty file
			if(fileBytes.length == 0)
			{
				//Return an empty location profile set
				return LocationProfileSet.generateBlankSet(getApplicationContext());
				
			}
			//Else, deserialize it
			java.io.ByteArrayInputStream tempIn = 
				new java.io.ByteArrayInputStream(fileBytes);
			LocationProfileSet result = null;
			try
			{
				result = (LocationProfileSet)
					((new java.io.ObjectInputStream(tempIn)).readObject());
			}
			catch(ClassNotFoundException err)
			{
				throw (IOException)(new IOException("Profile file contained an unknown object")).initCause(err);
			}
			catch(ClassCastException err)
			{
				throw (IOException)(new IOException("Profile file was of the wrong object type")).initCause(err);
			}
			return result;
		}
		finally
		{
			if(inStream != null)
				inStream.close();
		}
	}

	synchronized void initializeDaemon(LocationManager locMan)
	{
		if(currentProfileListener != null) { throw new IllegalStateException("There is already a profile set active"); }
		currentProfileListener = new ProfileListenerEngine(getCurrentProfiles());
		try
		{
			locMan.requestLocationUpdates(locMan.getBestProvider(ACCURACY_NEEDED, true), MIN_MILI_CHANGE_UPDATE,
					MIN_METER_CHANGE_UPDATE, currentProfileListener);
		}
		catch(RuntimeException err)
		{
			// Set not active on an exception
			currentProfileListener = null;
			throw err;
		}
		catch(Error err)
		{
			// Set not active on an exception
			currentProfileListener = null;
			throw err;
		}
	}
	
	synchronized final boolean isAppEnabled()
	{
		return currentProfileListener == null;
	}

	synchronized void stopDaemon(LocationManager locMan)
	{
		if(currentProfileListener == null) // If already inactive, do nothing
			return;
		// Stop the current listener
		locMan.removeUpdates(currentProfileListener);
		//Reset this to the default profile
		currentProfileListener.profiles.getDefaultProfile().settings.apply();
		//Close this out
		currentProfileListener = null;
	}
	
	public void setButton(View view)
	{
		Intent myIntent = new Intent(view.getContext(), ProfileList.class);
		myIntent.putExtra(ProfileList.PROFILES_SET, getCurrentProfiles());
		startActivityForResult(myIntent, 0);
	}
	
	public void createButton(View view)
	{
		Intent myIntent = new Intent(view.getContext(), ProfileName.class);
		myIntent.putExtra(ProfileList.PROFILES_SET, getCurrentProfiles());
		startActivityForResult(myIntent, 0);
	}
	
	public void editButton(View view)
	{
		Intent myIntent = new Intent(view.getContext(), ProfileList.class);
		myIntent.putExtra(ProfileList.PROFILES_SET, getCurrentProfiles());
		startActivityForResult(myIntent, 0);
	}
	
	public void disableButton(View view)
	{
		//Insert code for disable button here
	}
}